#include <iostream>
using namespace std;

class Box {
    public: //公有属性/方法, 外部可直接以对象属性形式访问
        static int objCount; 
            //静态变量, 自动初始化为0(不能在类内直接初始化)
            //可以在类外初始化
        double length;
        double getVolume(void) const; 
            //声明方法，可与定义分开, 方便以头文件方式引用?
            //如果直接在类中定义则编译器会尝试转化为内联函数
            //const 关键字表示保证该函数不会修改对象的属性值
        Box(){}; //无参构造函数，若不声明，则编译器提供一个默认的无参构造函数
        Box(double len); //构造函数(重载)
        Box(const Box &obj); //拷贝构造函数
        ~Box(); //析构函数
        friend void printHeight(Box box); 
            //友元函数, 无默认的类对象参数，需显式声明
        friend class Bottle; //友元类
        bool compareVolume(Box box);
        static int getCount(); //静态成员函数
        Box operator- (); //重载负号运算符
        Box operator- (Box const &box); //重载减号运算符
            //friend Box operator- (Box const &box1, Box const &box2);
            //以非成员函数方式重载类运算符
        friend ostream &operator<< (ostream &out, Box const &box);
            //重载输出运算符
        ostream &operator<< (ostream &out) const;
            //以成员函数形式重载输出运算符
        friend istream &operator>> (istream &in, Box const &box);
            //重载输入运算符
        Box operator- (int len); //重载减号
        friend Box operator-(int len, Box const &box); 
            //默认都是后置运算符重载，如果要支持交换顺序，可以定义相应的友元函数
        bool operator< (Box const &box);
        Box &operator=(Box const &box);
    protected: //受保护, 和私有修饰类似，不同的是其对象在子类中可访问
        double width;
    private: 
        //私有(默认修饰符, 如果在类声明起始位置则可省略)
        //外部不可修改，甚至不可查看?只有本类和友元函数可以访问?
        double height;
        int const *a = NULL;
};

Box &Box::operator=(Box const &box) {
    length = box.length;
    width = box.width;
    height = box.height;
    a = box.a;
    return *this;
}
ostream &Box::operator<< (ostream &out) const { 
    out << length << width << height << endl;
    return out;
}

ostream &operator<< (ostream &out, Box const &box) {
    return box << out;
}
bool Box::operator< (Box const &box) {
    return getVolume() < box.getVolume();
}


Box Box::operator- (int len) {
    Box box(*this);
    box.length -= len;
    return box;
}
Box operator-(int len, Box const &box) {
    Box tbox(box);
    tbox.length -= len;
    return tbox;
}
double Box::getVolume(void) const {
    return length*width* height; //可直接引用对象属性
}
Box::Box(double len) {
    //构造函数，创建对象时执行,名称和类名一致
    //不返回任何类型,形式上也不返回void(实际返回一个对象)
    //一般执行一些初始化操作
    //创建对象时的参数将传递给该函数
    //可声明并定义多个构造函数，创建对象时可有选择的调用不同函数
    //如果定义了构造函数那初始化时的参数必须和其中一个构造函数匹配
    length = len; //可直接引用对象属性
} 


Box::Box(const Box &obj) {
    //拷贝构造函数，只有一个同类对象的引用参数且无返回值
    //一般用于复制需要申请动态内存的对象。
    //默认的复制构造函数相当于浅拷贝      
}

Box::~Box(void) {
    //拷贝构造函数，只有一个同类对象的引用参数且无返回值
    //一般用于复制需要申请动态内存的对象。
    //默认的复制构造函数相当于浅拷贝      
}
 
void printHeight(Box box) {
    //类的友元函数可以访问该类对象的所有属性
    cout << "box height: " << box.height << endl;
}

//Box的友元类
class Bottle {
    double getBoxHeight(Box box);
};

double Bottle::getBoxHeight(Box box) {
    return box.height;
}

//this 指针是所有成员函数的隐形参数，指向当前对象
//也可以单独声明类指针，使用上同C的结构体： Box *pbox = NULL;
bool Box::compareVolume(Box box) {
    return this->getVolume() > box.getVolume();
}

int Box::getCount(void) { //不能再加static
    //没有this指针，只能访问静态成员(静态变量/函数)
    return objCount;
}


Box Box::operator-(void) {
    Box box(-length);
    box.width = -width;
    box.height = -height;
    return box;
}
Box Box::operator-(Box const &box) {
    Box tbox;
    tbox.width = width - box.width;
    tbox.height = height - box.height;
    return tbox;
}


istream &operator>> (istream &in, Box const &box) {
    in >> box.length >> box.width >> box.height;
    return in;
}

int Box::objCount = 0;

int main(void) 
{
    Box::getCount(); //类外引用静态函数
    Box b;
    b.getCount() + b.objCount; //也可以通过类实例引用
    return Box::objCount; //类外访问静态变量
}

